package com.apes.fn.server.productRequire;

import com.alibaba.druid.Constants;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.fn.scm.crossCompany.transfer.model.CrossCompanyTransferItemNew;
import com.apes.fn.scm.crossCompany.transfer.model.CrossCompanyTransferNew;
import com.apes.fn.scm.crossCompany.transfer.model.TransferProduct;
import com.apes.fn.scm.crossCompany.transfer.repository.CrossCompanyTransferItemNewRepository;
import com.apes.fn.scm.crossCompany.transfer.repository.CrossCompanyTransferNewRepository;
import com.apes.fn.scm.crossCompany.transfer.repository.TransferProductRepository;
import com.apes.fn.scm.crossCompany.transfer.service.CrossCompanyTransferNewService;
import com.apes.fn.server.servicePlan.service.ServiceToForeign;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.outbox.OutboxPayloadWrapper;
import com.apes.framework.plugin.outbox.OutboxSubscriberService;
import com.apes.framework.plugin.outbox.annotation.OutboxSubscriber;
import com.apes.framework.plugin.soe.store.database.repository.SceneRepository;
import com.apes.framework.util.DateUtil;
import com.apes.framework.util.MapUtil;
import com.apes.pi.service.PiManager;
import com.apes.scm.account.account.repository.InventoryBatchRepository;
import com.apes.scm.account.account.service.ProductAccountService;
import com.apes.scm.contract.repository.ContractRepository;
import com.apes.scm.masterdata.enumeration.model.BusinessParam;
import com.apes.scm.masterdata.enumeration.model.Enumeration;
import com.apes.scm.masterdata.enumeration.repository.BusinessParamRepository;
import com.apes.scm.masterdata.enumeration.repository.EnumerationRepository;
import com.apes.scm.masterdata.frame.service.StoreService;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apes.scm.masterdata.product.model.Product;
import com.apes.scm.masterdata.product.model.ProductUom;
import com.apes.scm.masterdata.product.repository.ProductRepository;
import com.apes.scm.masterdata.product.repository.ProductUomRepository;
import com.apes.scm.masterdata.stock.model.Location;
import com.apes.scm.masterdata.stock.repository.LocationRepository;
import com.apes.scm.pur.purchaseOrder.repository.PurchaseOrderRepository;
import com.apes.scm.rbac.model.User;
import com.apes.scm.rbac.repository.UserRepository;
import com.apes.scm.stock.safetyStock.model.SafetyStockGap;
import com.apes.scm.stock.safetyStock.repository.SafetyStockGapRepository;
import com.apes.scm.stock.transfer.model.Pick;
import com.apes.scm.stock.transfer.model.Transfer;
import com.apes.scm.stock.transfer.model.TransferItem;
import com.apes.scm.stock.transfer.repository.PickRepository;
import com.apes.scm.stock.transfer.repository.TransferItemRepository;
import com.apes.scm.stock.transfer.repository.TransferRepository;
import com.apes.scm.voucher.service.builder.CrossTransferVoucherBuilder;
import com.apestech.framework.util.StringUtil;
import com.google.common.util.concurrent.AtomicDouble;
import lombok.Data;
import org.apache.commons.collections.map.HashedMap;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.event.EventListener;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.StringUtils;

import javax.persistence.EntityManager;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service("autoProductRequireDumpService")
public class AutoProductRequireDumpService extends DomainService {
    @Autowired
    private ProductRequireRepository productRequireRepository;
    @Autowired
    private ProductRequireItemRepository productRequireItemRepository;
    @Autowired
    private LocationRepository locationRepository;
    @Autowired
    private ProductUomRepository productUomRepository;
    @Autowired
    private EnumerationRepository enumerationRepository;
    @Autowired
    private ProductRepository productRepository;
    @Autowired
    private ProductRequireExpandRepository productRequireExpandRepository;
    @Autowired
    private PartyRoleRepository partyRoleRepository;
    @Autowired
    private TransferRepository transferRepository;
    @Autowired
    private CrossCompanyTransferNewRepository crossCompanyTransferNewRepository;
    @Autowired
    private BusinessParamRepository businessParamRepository;
    @Autowired
    private SafetyStockGapRepository safetyStockGapRepository;
    @Autowired
    private ProductAccountService productAccountService;
    @Autowired
    private InventoryBatchRepository inventoryBatchRepository;
    @Autowired
    private ProductRequireService productRequireService;
    @Autowired
    private TransferProductRepository transferProductRepository;
    @Autowired
    private PiManager piManager;
    @Autowired
    private EntityManager entityManager;
    @Autowired
    private OutboxSubscriberService outboxSubscriberService;
    @Autowired
    private ServiceToForeign serviceToForeign;
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private StoreService storeService;

    @Value("${apes.switched:false}")
    private Boolean switched;







    /** 老切新-生成新老框架采购订单处理 */
    private void createPurchaseNewAndOld(String requireId) {
        if (true) return;
        List existsRequirePurchase = SpringManager.getBean(PurchaseOrderRepository.class).findAll("SELECT 1 FROM PUR_PURCHASE_ORDER WHERE SOURCE = '"+ requireId +"' AND PRODUCT_REQUIRE_ID = '" + requireId + "' AND SUPPLIER_TYPE NOT LIKE '%巴图鲁采%'");
        if (existsRequirePurchase.size() > 0) return; // 自动转储时仅生成一次采购
        Map condi = new HashMap();
        condi.put("id", requireId);
        condi.put("commodityInquiryOrderId", true);
        condi.put("purchaseGroupIdIsNotNull", true);
        List queryRequireItem = new ArrayList();
        try {
            queryRequireItem = invoke("stock.replenishmentManagementService.queryRequireItem", condi);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (queryRequireItem.size() == 0) return;
        queryRequireItem.stream().forEach(item -> {
            Map itemap = (HashMap) item;
            itemap.put("selectFlag", true);
            itemap.put("checkData", true);
        });
        JSONObject itemObj = new JSONObject();

        itemObj.put("productRequireItems", JSONArray.parseArray(JSON.toJSONString(queryRequireItem)));
        itemObj.put("originMethod", "createPurchaseNewAndOld");
        JSONObject getRequirePrice = invoke("stock.replenishmentManagementService.purchaseNeedInfo", itemObj);
        getRequirePrice.remove("productRequireItems");
        JSONArray newPurchaseRequireItems = getRequirePrice.getJSONArray("purchaseRequireItems").stream().filter(item -> ((JSONObject) item).getDoubleValue("P001") > 0).collect(Collectors.toCollection(JSONArray::new));
        if (newPurchaseRequireItems.size() == 0) return;
        getRequirePrice.put("purchaseRequireItems", newPurchaseRequireItems);
        getRequirePrice.put("note", "要货自动补货-采购");
        getRequirePrice.put("UUID", StringUtil.getUUID());
        try {
            outboxSubscriberService.commonSendRequest("local:autoProductRequireDumpService.insertPurchaseOrder", "autoProductRequireDumpService.requireId" + requireId, getRequirePrice);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }



    /** 批量修改要货单 */
    private void updateReuqire(List<ProductRequire> requires) {
        requires.forEach(productrequire -> {
            productrequire.checkComplete();
            ProductRequire require = productRequireRepository.save(productrequire);
            if ("complete".equals(productrequire.getState())) invoke("stock.productRequireService.sendToApp", productRequireRepository.findOne(require.getId()));
        });
    }


    /**
     *
     * @param singleRequireItem
     * @param fcLocationInfo
     * @param isNotCross
     * @param transferItems
     * @param crossCompanyTransferItems
     * @param isSatisfyInventoryAllocation 库存一次性满足缺口数才分配
     * @return
     */
    public boolean dumpDistribution(Map singleRequireItem, Location fcLocationInfo, Location cLocation, boolean isNotCross, Set<TransferItem> transferItems, Set<CrossCompanyTransferItemNew> crossCompanyTransferItems,
                                     boolean isSatisfyInventoryAllocation, Map dumpProductUoms, Map requireUoms, Map cacheUomFactory1) {
        String requireProductId = singleRequireItem.get("PRODUCT_ID").toString();
        ProductUom dumpProductUom = new ProductUom();
        ProductUom requireUom = new ProductUom();
        if (dumpProductUoms.get(requireProductId) == null) {
            dumpProductUom = productUomRepository.findAll(JpaDsl.toCriteriaByEq("uomCategory.id", requireProductId, "transferFirst", true)).get(0);
            dumpProductUoms.put(requireProductId, dumpProductUom);
        } else {
            dumpProductUom = (ProductUom) dumpProductUoms.get(requireProductId);
        }
        if (requireUoms.get(requireProductId) == null) {
            requireUom = productUomRepository.findAll(JpaDsl.toCriteriaByEq("uomCategory.id", requireProductId, "id", singleRequireItem.get("PRODUCT_UOM_ID"))).get(0);
            requireUoms.put(requireProductId, requireUom);
        } else {
            requireUom = (ProductUom) requireUoms.get(requireProductId);
        }
        double rabbet = Double.parseDouble(singleRequireItem.get("RABBET").toString());
        AtomicDouble newRabbet = new AtomicDouble(Math.ceil(requireUom.computeQty(rabbet, dumpProductUom, false)));

//        this.saveDumpLog(fcLocationInfo.getId(), cLocation.getId(), requireProductId, "具体跟踪：newRabbet.get() <= 0 ===>" + newRabbet.get());
        if (newRabbet.get() <= 0) return true;

        // 有效库存
        Map allStocks = new HashMap();

        // 跨公司调拨 [赋能-赋能] 查询库存带供应商，[直营-赋能] 查询库存方式跟转储一样
        String supplierLog = "";
        String shipOperation = SpringManager.getBean(CrossTransferVoucherBuilder.class).getModel(fcLocationInfo.getCompany());
        String receptionOperation = SpringManager.getBean(CrossTransferVoucherBuilder.class).getModel(cLocation.getCompany());
        String export = "empower".equals(shipOperation)?"001073":"subsidiary".equals(shipOperation)?"001661":"001072";
        String reception = "empower".equals(receptionOperation)?"001073":"subsidiary".equals(receptionOperation)?"001661":"001072";
        List<TransferProduct> transferProductList = transferProductRepository.findByALL(export, reception);
        TransferProduct supplierIsNull = transferProductList.stream().filter(transferProduct -> transferProduct.getSupplier() == null).findFirst().orElse(null);
        if (supplierIsNull != null) {
            allStocks = productRequireItemRepository.availableStockAllSupplier(fcLocationInfo.getId(), requireProductId);
        } else {
            List supplierIds = new ArrayList();
            if ("001073".equals(export)&& !"001073".equals(reception)) {
                List<TransferProduct> transferProductListContract = SpringManager.getBean(CrossCompanyTransferNewService.class).checkTransferProduct(transferProductList,true);
                supplierIds = transferProductListContract.stream().map(transferProduct -> transferProduct.getSupplier().getId()).distinct().collect(Collectors.toList());
                allStocks = productRequireItemRepository.availableStockSupplier(fcLocationInfo.getId(), requireProductId, supplierIds);
            } else {
                supplierIds = transferProductList.stream().map(transferProduct -> transferProduct.getSupplier().getId()).distinct().collect(Collectors.toList());
                allStocks = productRequireItemRepository.availableStockSupplier(fcLocationInfo.getId(), requireProductId, supplierIds);
            }
            if (supplierIds.size() > 0) {
                for (int i = 0, iLen = supplierIds.size(); i < iLen; i++) {
                    supplierLog += supplierIds.get(i) + ";";
                }
            }


        }


//        this.saveDumpLog(fcLocationInfo.getId(), cLocation.getId(), requireProductId, "是否无库存 ===>" + allStocks.isEmpty() + ", 条件供应商:" + supplierLog);
        if (allStocks.isEmpty()) return false;

        ProductUom stockUom = new ProductUom();
        if (cacheUomFactory1.get(requireProductId) != null) {
            stockUom = (ProductUom) cacheUomFactory1.get(requireProductId)/*productUomRepository.findAll(JpaDsl.toCriteriaByEq("uomCategory.id", requireProductId, "factor", 1)).get(0)*/;
        } else {
            stockUom = productUomRepository.findAll(JpaDsl.toCriteriaByEq("uomCategory.id", requireProductId, "factor", 1)).get(0);
            cacheUomFactory1.put(requireProductId, stockUom);
        }

        Product product = productRepository.findOne(requireProductId);
        double usableQty = Double.parseDouble(allStocks.get("USABLE_QTY").toString());
        double newUsableQty = Math.floor(stockUom.computeQty(usableQty, dumpProductUom, false));

//        this.saveDumpLog(fcLocationInfo.getId(), cLocation.getId(), requireProductId, "缺口数量小于 0 || 可用数小于 0 ===> " + newRabbet.get() + ";" + newUsableQty);
        if (newRabbet.get() <= 0 || newUsableQty <= 0) return true;

//        this.saveDumpLog(fcLocationInfo.getId(), cLocation.getId(), requireProductId, "是否区域仓 ===> " + isSatisfyInventoryAllocation + ";" + (newUsableQty < newRabbet.get()));
        if (isSatisfyInventoryAllocation == true && newUsableQty < newRabbet.get()) return true; // 满足库存才分配

        double dumpQty = newRabbet.get() > newUsableQty?newUsableQty:newRabbet.get();
        newRabbet.getAndSet(newRabbet.get() - dumpQty);

        // 数量分配判断
        if (isNotCross) {
//            this.saveDumpLog(fcLocationInfo.getId(), cLocation.getId(), requireProductId, "不是跨公司数据拼接");
            this.appendTransferItem(product, dumpProductUom, dumpQty, transferItems);
        } else {
//            this.saveDumpLog(fcLocationInfo.getId(), cLocation.getId(), requireProductId, "跨公司数据拼接");
            this.appendCrossCompanyTransferItem(product, dumpProductUom, dumpQty, newUsableQty, crossCompanyTransferItems);
        }
        return false;
    }

    /** 跨公司调拨获取有效库存
     * 规则一: 根据收发货公司获取调拨范围获取供应商
     * 规则二: 直营转赋能只有合同才能调拨, 防止调拨下去后找门店结算
     * */
    public Map getVaildStock(String fOperator, String cOperator, String fLocationId, String productId/*, Map availableStocks*/) {
        Map availableStocks = new HashMap();
        List<TransferProduct> transferProductList = transferProductRepository.findByALL(fOperator, cOperator); // 规则一
        TransferProduct supplierIsNull = transferProductList.stream().filter(transferProduct -> transferProduct.getSupplier() == null).findFirst().orElse(null);
        if (supplierIsNull != null) {
            availableStocks = productRequireItemRepository.availableStockAllSupplier(fLocationId, productId);
            if ("001072".equals(fOperator) && "001073".equals(cOperator)) availableStocks = productRequireItemRepository.availableStockAllSupplierContract(fLocationId, productId); // 规则二
        } else if (transferProductList.size() != 0) {
            List supplierIds = transferProductList.stream().map(transferProduct -> transferProduct.getSupplier().getId()).distinct().collect(Collectors.toList());
            availableStocks = productRequireItemRepository.availableStockSupplier(fLocationId, productId, supplierIds);
            if ("001072".equals(fOperator) && "001073".equals(cOperator)) availableStocks = productRequireItemRepository.availableStockSupplierContract(fLocationId, productId, supplierIds);
        }
        return availableStocks;
    }

    /** 转储订单 保存 */
    private Transfer transferSaveIsNotCross(Set<TransferItem> transferItems, Location fLocationInfo, Location cLocationInfo, String note, String source, String sourceBusinessType, String personId) {
        Transfer transfer = new Transfer();
        PartyRole system = new PartyRole();
        if (!StringUtils.isEmpty(personId)) {
            system = partyRoleRepository.findOne(personId);
//            transfer.setCreateUid(system);
        } else {
            system = SpringManager.getBean(PartyRoleRepository.class).findOne("system");
//            transfer.setCreator(system.getId());
//            transfer.setCreateUid(system);
        }
//        PartyRole system = SpringManager.getBean(PartyRoleRepository.class).findOne("system");
        transfer.setCreator(system.getId());
        transfer.setCreateUid(system);
        List<User> userInfo = SpringManager.getBean(UserRepository.class).findAll(JpaDsl.toCriteriaByEq("person.id", system.getId()));
        transfer.setUserId(userInfo.get(0).getId().toString());
        if (transferItems.size() == 0) return transfer;
        transfer.setTransferItems(transferItems);
        appendTransfer(fLocationInfo, cLocationInfo, note, transfer, source, sourceBusinessType);
        transfer.setCreator(system.getId());
        transfer = invoke("stock.transfer.autoRequireTransfer", transfer);
        transfer = transferRepository.findOne(transfer.getId());
        transfer.setApproveUid(system);
        transfer = invoke("stock.transfer.approve", transfer);
        return transfer;
    }

    /** 跨公司订单 保存*/
    private CrossCompanyTransferNew crossSaveIsNotCross(Set<CrossCompanyTransferItemNew> crossCompanyTransferItems, Location fLocationInfo, Location cLocationInfo, String note,
                                                        String source, String sourceBusinessType, String personId) {
        CrossCompanyTransferNew crossCompanyTransferNew = new CrossCompanyTransferNew();
        PartyRole system = new PartyRole();
        if (crossCompanyTransferItems.size() == 0) return crossCompanyTransferNew;
        if (!StringUtils.isEmpty(personId)) {
            system = partyRoleRepository.findOne(personId);
            crossCompanyTransferNew.setCreateUid(system);
        } else {
            system = SpringManager.getBean(PartyRoleRepository.class).findOne("system");
            crossCompanyTransferNew.setCreator(system.getId());
            crossCompanyTransferNew.setCreateUid(system);
        }
        crossCompanyTransferNew.setCrossCompanyTransferItems(crossCompanyTransferItems);

        List<User> userInfo = SpringManager.getBean(UserRepository.class).findAll(JpaDsl.toCriteriaByEq("person.id", system.getId()));
        crossCompanyTransferNew.setUserId(userInfo.get(0).getId().toString());
        this.appendCrossCompanyTransfer(fLocationInfo, cLocationInfo, note, crossCompanyTransferNew, source, sourceBusinessType);

        crossCompanyTransferNew = invoke("cross.company.transferNew.save", crossCompanyTransferNew);
        if (crossCompanyTransferNew == null) return null;
        crossCompanyTransferNew = crossCompanyTransferNewRepository.findOne(crossCompanyTransferNew.getId());
        crossCompanyTransferNew.setApproveUid(crossCompanyTransferNew.getCreateUid());
        crossCompanyTransferNew = invoke("cross.company.transferNew.approve", crossCompanyTransferNew);
        return crossCompanyTransferNew;
    }


/*    *//** [转储、跨公司] 终止 *//*
    public void requireExpandDumpCacel(SimpleRequest request) {
        JSONObject getJO = request.getJO();
        String id = getJO.getString("id");
        String innerBusinessType = getJO.getString("innerBusinessType");
        if ("Transfer".equals(innerBusinessType)) {
            Transfer transfer = transferRepository.findOne(id);
            transfer.getTransferItems().forEach(transferItem -> {
                String productId = transferItem.getProduct().getId();
                long uom = transferItem.getUom().getId();
                this.dumpDealWithQty(transfer.getId(), transferItem.getFinishSum(), productId, uom, 0, 0);

            });
        } else if ("CrossCompanyTransferNew".equals(innerBusinessType)) {
            CrossCompanyTransferNew crossMain = crossCompanyTransferNewRepository.findOne(id);
            crossMain.getCrossCompanyTransferItems().forEach(crossItem -> {
                String productId = crossItem.getProduct().getId();
                long uom = crossItem.getUom().getId();
                this.dumpDealWithQty(crossMain.getId(), crossItem.getFinishSum(), productId, uom, 0, 0);
            });
        }
    }*/

    /** [转储、跨公司] 终止、收货、发货 回写对应数量
     * id 来源单据号
     * dumpQty 转储数量
     * productId 商品ID
     * dumpUomId 计量单位ID
     * arriveQty 到货数量
     * shipQty 发货数量
     * */
    /*public void dumpDealWithQty(String id, double dumpQty, String productId, long dumpUomId, double arriveQty, double shipQty) {
        AtomicDouble latestQty = new AtomicDouble(dumpQty>0?dumpQty:arriveQty>0?arriveQty:shipQty>0?shipQty:0);
        List<Map> qryCanCancelDatas = productRequireExpandRepository.qryCanCancelData(id, productId);
        if (qryCanCancelDatas.size() == 0) return;
        qryCanCancelDatas.stream().anyMatch(singleCancelRequireExpand -> { // 可终止转储分配扩展信息
            if (latestQty.get() <= 0) return true;
            String distributionId = singleCancelRequireExpand.get("DISTRIBUTION_ID").toString();//配货单号
            String originItemId = singleCancelRequireExpand.get("ORIGIN_ITEM_ID").toString();//原始明细编码
            String originBusinessType = singleCancelRequireExpand.get("ORIGIN_BUSINESS_TYPE").toString();//源单据类型
            double originQty = Double.parseDouble(singleCancelRequireExpand.get("REQUIRE_QTY").toString());//原始数量

            List findSpecialDocumentsTypes = sendSynEvent("event:fn.crossCompanyTransferNewService.findSpecialDocumentsType", new JSONObject(MapUtil.mapper("id", distributionId)));
            if (!findSpecialDocumentsTypes.isEmpty() && "要货补货转储新逻辑 - 后面要剔除".equals(findSpecialDocumentsTypes.get(0))) return true;

            // 修改转储分配扩展信息
            double newQty = updateRequireExpand(dumpQty, arriveQty, shipQty, latestQty.get(), distributionId, originItemId, singleCancelRequireExpand);

            // 修改 要货、安全库存 明细
            ProductUom dumpUom = productUomRepository.findOne(dumpUomId);
            if ("ProductRequire".equals(originBusinessType)) {
                ProductRequireItem requireItem = productRequireItemRepository.findOne(originItemId);
                if (Objects.isNull(requireItem)) return false;
                double changeArriveQty = newQty == 0?0:dumpUom.computeQty(arriveQty > newQty?newQty:arriveQty, requireItem.getUom(), false);
                ProductRequire require = productRequireService.updateRequireQty("", originItemId, "", 0, changeArriveQty, dumpUom.computeQty(dumpQty>0?-1 * newQty:0, requireItem.getUom(), false));
                if (dumpQty != 0) {
                    Location requireLocation = requireItem.getProductRequire().getLocation();
                    String requireId = requireItem.getProductRequire().getId();
                    String requireInnerBusiinessType = requireItem.getProductRequire().getInnerBusinessType();
                    double compareDumpQty = dumpUom.computeQty(dumpQty, requireItem.getUom(), false);
                    double compareOriginQty = dumpUom.computeQty(originQty, requireItem.getUom(), false);
                    List innerBusinessTypes = productRequireRepository.findAll("SELECT INNER_BUSINESS_TYPE FROM PUR_PURCHASE_ORDER T WHERE ID = '"+ distributionId +"'");
                    String innerBusinessType = innerBusinessTypes.size() != 0?innerBusinessTypes.get(0).toString():"";
                    if (!"PurchaseOrder".equals(innerBusinessType)) productAccountService.setProductRequireBilling(requireItem.getProduct(), requireLocation, requireItem.getUom(),
                            compareDumpQty>compareOriginQty?compareOriginQty:compareDumpQty, requireInnerBusiinessType, requireId, originItemId, "要货批量转储终止", requireLocation.getCompany(), requireId);
                }
                require.checkComplete();
                require = productRequireRepository.save(require);
                if ("complete".equals(require.getState())) invoke("stock.productRequireService.sendToApp", productRequireRepository.findOne(require.getId()));
            } else {
                ProductUom uom = productUomRepository.findAll(JpaDsl.toCriteriaByEq("uomCategory.id", productId, "factor", 1)).get(0);
                updateSafetyStockGap(dumpUom, uom, originItemId, dumpQty>0?-1 * newQty:0, arriveQty>0?newQty:0);
            }

            latestQty.getAndSet(latestQty.get() - newQty);
            return false;
        });
    }*/

    /** [转储、跨公司] 终止、收货、发货 -----> 修改转储分配扩展信息 */
    private double updateRequireExpand(double dumpQty, double arriveQty, double shipQty, double latestQty, String distributionId, String requireItemId, Map singleCancelRequireExpand) {
        String sql = "UPDATE STOCK_PRODUCT_REQUIRE_EXPAND SET ";
        double newQty = 0;
        if (dumpQty != 0) {
            double cancelQty = Double.parseDouble(singleCancelRequireExpand.get("CANCEL_QTY").toString());
            newQty = latestQty > cancelQty?cancelQty:latestQty;
            sql += " CANCEL_QTY = CANCEL_QTY + " + newQty;
        } else if (arriveQty > 0) {
            double expandArriveQty = Double.parseDouble(singleCancelRequireExpand.get("ARRIVE_QTY").toString());
            newQty = latestQty > expandArriveQty?expandArriveQty:latestQty;
            sql += " ARRIVE_DATE = SYSDATE, ARRIVE_QTY = ARRIVE_QTY + " + newQty;
        } else if (shipQty > 0) {
            double expandShipQty = Double.parseDouble(singleCancelRequireExpand.get("SHIP_QTY").toString());
            newQty = latestQty > expandShipQty?expandShipQty:latestQty;
            sql += " SHIP_QTY = SHIP_QTY + " + newQty;
        } else {
            throw new RuntimeException("自动要货转储: 未找到对应要货单! ");
        }
        sql += " WHERE DISTRIBUTION_ID = '" + distributionId + "' AND ORIGIN_ITEM_ID = '" + requireItemId + "'";
        productRequireExpandRepository.exec(sql);
        return newQty;
    }

    /** 安全库存缺口 -----> 修改分配、到货数量 */
    private void updateSafetyStockGap(ProductUom dumpUom, ProductUom uom, String id, double assignQty, double arriveQty) {
        if (assignQty == 0 && arriveQty == 0) return;
        double newAssignQty = dumpUom.computeQty(assignQty, uom, false);
        String oldSql = "UPDATE RPT_AQKCQKRBB SET ";
        if (arriveQty > 0) {
            oldSql += " YRKSL = YRKSL + " + arriveQty;
        }
        if (assignQty != 0) {
            oldSql += " ZCSL = ZCSL + " + newAssignQty;
        }
        this.updateStockGap(id, "", "", "", arriveQty, newAssignQty);

        // 仓储公司-安全库存新框架补货同步老框架
        Map stockGap = safetyStockGapRepository.accordingIdQuery(Long.parseLong(id));
        oldSql += " WHERE TJRQ = GET_DATE() AND CKKQID = '" + stockGap.get("LOCATION_ID") + "' AND SPID = '" + stockGap.get("PRODUCT_ID") + "'";
        JSONObject oldParam = new JSONObject();
        oldParam.put("sql", oldSql);
        if (switched) return;
        piManager.synErp("autoService.updateOriginNewFrame", oldParam);

    }

    /** 修改安全库存: 提供给第三方用*/
    public void forThirdPartiesStockGap(SimpleRequest request) {
        JSONObject getJO = request.getJO();
        String id = getJO.getString("id");
        String locationId = getJO.getString("locationId");
        String productId = getJO.getString("productId");
        String statisticsDate = getJO.getString("statisticsDate");
        double arriveQty = getJO.getDoubleValue("arriveQty");
        double newAssignQty = getJO.getDoubleValue("newAssignQty");
        this.updateStockGap(id, locationId, productId, statisticsDate, arriveQty, newAssignQty);
    }

    /** 修改安全库存 */
    private void updateStockGap(String id, String locationId, String productId, String statisticsDate, double arriveQty, double newAssignQty) {
        String sql = "UPDATE STOCK_SAFETY_GAP SET ";
        if (arriveQty != 0) sql += " WAREHOUSING_QTY = WAREHOUSING_QTY + " + arriveQty;
        if (newAssignQty != 0) sql += " ASSIGNED_QTY = ASSIGNED_QTY + " + newAssignQty;
        sql += " WHERE 1 = 1 ";
        if (!StringUtils.isEmpty(id)) sql += " AND ID = '" + id + "'";
        if (!StringUtils.isEmpty(locationId)) sql += " AND LOCATION_ID = '" + locationId + "'";
        if (!StringUtils.isEmpty(productId)) sql += " AND PRODUCT_ID = '" + productId + "'";
        if (!StringUtils.isEmpty(statisticsDate)) sql += " AND TO_DATE(TO_CHAR(STATISTICS_DATE, 'YYYY/MM/DD'), 'YYYY/MM/DD') = TO_DATE('"+ statisticsDate +"', 'YYYY/MM/DD')";
        safetyStockGapRepository.exec(sql);
    }

    /** 收货、发货 */
/*    public void receiptAndDelivery(SimpleRequest request) {
        JSONObject getJO = request.getJO();
        String pickId = getJO.getString("pickId");
        Pick pick = SpringManager.getBean(PickRepository.class).findOne(pickId);
        String dumpId = pick.getOrigin();
        String dumpType = pick.getOriginBusinessType();
        if (!"Transfer".equals(dumpType) && !"CrossCompanyTransferNew".equals(dumpType)) return;
        pick.getPickItems().forEach(pickItem -> {
            String productId = pickItem.getProduct().getId();
            long dumpUomId = 0;
            if ("Transfer".equals(dumpType)) dumpUomId = SpringManager.getBean(TransferItemRepository.class).findAll(JpaDsl.toCriteriaByEq("transfer.id", dumpId, "product.id", productId)).get(0).getUom().getId();
            if ("CrossCompanyTransferNew".equals(dumpType)) dumpUomId = SpringManager.getBean(CrossCompanyTransferItemNewRepository.class).findAll(JpaDsl.toCriteriaByEq("crossCompanyTransfer.id", dumpId, "product.id", productId)).get(0).getUom().getId();
            if ("deliver".equals(pick.getOperation())) this.dumpDealWithQty(dumpId, 0, productId, dumpUomId, 0, pickItem.getQtyDone()); // 发货
            if ("receipt".equals(pick.getOperation())) this.dumpDealWithQty(dumpId, 0, productId, dumpUomId, pickItem.getQtyDone(), 0); // 收货
        });
    }*/

    /** 拼接转储订单 */
    private void appendTransfer(Location fLocationId, Location cLocationId, String note, Transfer transfer, String source, String sourceBusinessType) {
        if ("SafetyStockGap".equals(sourceBusinessType)) {
            transfer.setSpecialDocuments(source);
            transfer.setSpecialDocumentsType(sourceBusinessType);
        } else {
            transfer.setSource(source);
            transfer.setSourceBusinessType(sourceBusinessType);
        }
        transfer.setScene(SpringManager.getBean(SceneRepository.class).findOne("PT001"));
        transfer.setOriginLocation(fLocationId);
        transfer.setReceiptLocation(cLocationId);
        transfer.setCompany(cLocationId.getCompany());
        transfer.setNote(note);
        transfer.setReason(enumerationRepository.findOne("000180"));
        transfer.setState("sent");
        transfer.setCross(transfer.checkCross());
        if (transfer.checkAuto()) {
            transfer.setTransferType(enumerationRepository.findOne("000164"));
        } else {
            transfer.setTransferType(enumerationRepository.findOne("000165"));
        }
    }

    /** 拼接转储订单明细 */
    private Map appendTransferItem(Product product, Map dumpParam/*ProductUom uom, double dumpQty*/) {
        ProductUom dumpUom = (ProductUom) dumpParam.get("dumpUom");
        double dumpQty = (double) dumpParam.get("dumpQty");
        return MapUtil.mapper("product", MapUtil.mapper("id", product.getId()), "uom", MapUtil.mapper("id", dumpUom.getId()), "transferQty", dumpQty, "originItemId", dumpParam.get("id"));
    }

    /** 拼接转储订单明细 */
    private void appendTransferItem(Product product, ProductUom uom, double dumpQty, Set<TransferItem> transferItems) {
        TransferItem transferItem = new TransferItem();
        transferItem.setProduct(product);
        transferItem.setUom(uom);
        transferItem.setTransferQty(dumpQty);
        transferItems.add(transferItem);
    }

    /** 拼接跨公司调拨数据 */
    private void appendCrossCompanyTransfer(Location fLocationId, Location cLocationId, String note, CrossCompanyTransferNew crossCompanyTransferNew, String source, String sourceBusinessType) {
        if ("SafetyStockGap".equals(sourceBusinessType)) {
            crossCompanyTransferNew.setSpecialDocuments(source);
            crossCompanyTransferNew.setSpecialDocumentsType(sourceBusinessType);
        } else {
            crossCompanyTransferNew.setSource(source);
            crossCompanyTransferNew.setSourceBusinessType(sourceBusinessType);
        }

        crossCompanyTransferNew.setCompany(cLocationId.getCompany());
        crossCompanyTransferNew.setShipLocation(fLocationId);
        crossCompanyTransferNew.setReceiptLocation(cLocationId);
        crossCompanyTransferNew.setReturnReason(enumerationRepository.findOne("000180"));
        crossCompanyTransferNew.setState("sent");
        crossCompanyTransferNew.setNote(note);
        crossCompanyTransferNew.setAuto(true);
    }

    /** 拼接跨公司调拨明细数据 */
    private Map appendCrossCompanyTransferItem(Product product, Map dumpParam) {
        ProductUom dumpUom = (ProductUom) dumpParam.get("dumpUom");
        double dumpQty = (double) dumpParam.get("dumpQty");
        double newUsableQty = (double) dumpParam.get("newUsableQty");
        return MapUtil.mapper("product", MapUtil.mapper("id", product.getId()), "uom", MapUtil.mapper("id", dumpUom.getId()),
                "productSumQty", newUsableQty, "productSum", dumpQty, "originItemId", dumpParam.get("id"));
    }

    /** 拼接跨公司调拨明细数据 */
    private void appendCrossCompanyTransferItem(Product product, ProductUom uom, double dumpQty, double newBalanceQty, Set<CrossCompanyTransferItemNew> crossCompanyTransferItems) {
        CrossCompanyTransferItemNew crossCompanyTransferItemNew = new CrossCompanyTransferItemNew();
        crossCompanyTransferItemNew.setProduct(product);
        crossCompanyTransferItemNew.setUom(uom);
        crossCompanyTransferItemNew.setProductSumQty(newBalanceQty);
        crossCompanyTransferItemNew.setProductSum(dumpQty);
        crossCompanyTransferItems.add(crossCompanyTransferItemNew);
    }

    /** 要货扩展信息 */
    private void dealWithRequireExpandInfo(String requireId, String originBusinessType, Product product, String requireItemId, ProductUom uom, String distributionId, double requireQty, double assignQty) {
        ProductRequireExpand productRequireExpand = new ProductRequireExpand();
        productRequireExpand.setOrigin(requireId);
        productRequireExpand.setOriginItemId(requireItemId);
        productRequireExpand.setOriginBusinessType(originBusinessType);
        productRequireExpand.setProductId(product);
        productRequireExpand.setProductUomId(uom);
        productRequireExpand.setDistributionId(distributionId);
        productRequireExpand.setRequireQty(requireQty);
        productRequireExpand.setAssignQty(assignQty);
        invoke("stock.productRequireExpand.save", productRequireExpand);
    }

    /** 格式化要货单明细 */
    private void formatYHDMX(ProductRequire require, Map requireItem, JSONArray requireItemArray) {
        JSONObject requireItemObj = new JSONObject();
        requireItemObj.put("YHDH", requireItem.get("PRODUCT_REQUIRE_ID"));
        requireItemObj.put("XH", requireItem.get("ID"));
        requireItemObj.put("SPID", requireItem.get("PRODUCT_ID"));

        Product product = productRepository.findOne(requireItem.get("PRODUCT_ID").toString());
        requireItemObj.put("SPMC", product.getName());
        requireItemObj.put("PLID", product.getClassify().getId());
        requireItemObj.put("PLMC", product.getClassify().getName());
        requireItemObj.put("PPID", product.getBrand().getId());
        requireItemObj.put("PPMC", product.getBrand().getName());
        requireItemObj.put("SPZID", product.getProductGroup().getId());
        requireItemObj.put("SPZMC", product.getProductGroup().getName());
        requireItemObj.put("SPXH", product.getModel());
        requireItemObj.put("GG", product.getSpecifications());
        requireItemObj.put("BZSM", product.getDescription());

        ProductUom uom = productUomRepository.findOne(Long.parseLong(requireItem.get("PRODUCT_UOM_ID").toString()));
        requireItemObj.put("JLDW", uom.getName());
        requireItemObj.put("HSBL", uom.getFactor());
        requireItemObj.put("YHJS", Double.parseDouble(requireItem.get("QTY_REQUIRE").toString()) / uom.getFactor());
        requireItemObj.put("YHSL", Double.parseDouble(requireItem.get("QTY_REQUIRE").toString()));
        requireItemObj.put("ZY", requireItem.get("REMARK"));
        requireItemObj.put("GSID", requireItem.get("COMPANY_ID"));
        requireItemObj.put("XJDH", requireItem.get("COMMODITY_INQUIRY_ORDER_ID")); // 询价单号
        requireItemObj.put("YFPJS", Double.parseDouble(requireItem.get("QTY_ASSIGNED").toString()) / uom.getFactor());
        requireItemObj.put("YFPSL", Double.parseDouble(requireItem.get("QTY_ASSIGNED").toString()));
        requireItemObj.put("YZZJS", 0);
        requireItemObj.put("YZZSL", 0);
        requireItemObj.put("YJXSZQ_SJ", 0);
        requireItemObj.put("JXL_R7", 0);
        requireItemObj.put("JXL_R30", 0);
        requireItemObj.put("AQKC", 0);
        requireItemObj.put("SJKCSL", 0);
        requireItemObj.put("CCSL", 0);
        requireItemObj.put("ZTSL", 0);
        requireItemObj.put("CGSL", 0);
        requireItemObj.put("ZCSL", 0);
        requireItemObj.put("CGCKJ", 0);
        requireItemObj.put("DHJS", 0);
        requireItemObj.put("DHSL", 0);
        requireItemObj.put("CGJHSL", 0);
        requireItemObj.put("YJDHSC", 0);
        requireItemObj.put("DHDJ", 0);
        requireItemObj.put("KJHJS", 0);
        requireItemObj.put("ZGXL", 0);
        requireItemObj.put("SJDHSL", 0);
        requireItemObj.put("FWLXID", require.getServeType().getId());
        requireItemObj.put("FWLXMC", require.getServeType().getName());
        requireItemObj.put("FXTTJBJ", 0);
        requireItemObj.put("FJYSPBJ", 0);
        requireItemObj.put("DZJGBJ", 0);
        requireItemObj.put("DZKCBJ", 0);
        requireItemObj.put("DZPPBJ", 0);
        if (product.getCategory() != null) {
            requireItemObj.put("PJMCID", product.getCategory().getId());
            requireItemObj.put("PJMC", product.getCategory().getName());
        }
        requireItemObj.put("HYZT", 1);
        requireItemArray.add(requireItemObj);
    }

    /** 拼接老框架安全库存缺口 */
    private void appendAQKCQK(List<SafetyStockGap> safetyStockGaps) {
        JSONArray array = new JSONArray();
        safetyStockGaps.stream().forEach(safetyStockGap -> {
            if (!safetyStockGap.getLocation().getCompany().getParty().isWarehousingCompany()) {
                JSONObject safetyStockGapsObj = new JSONObject();
                Product product  = safetyStockGap.getProduct();
                Location location = safetyStockGap.getLocation();
                safetyStockGapsObj.put("TJRQ", safetyStockGap.getStatisticsDate());
                safetyStockGapsObj.put("CKKQID", location.getId());
                safetyStockGapsObj.put("CKKQMC", location.getName());
                safetyStockGapsObj.put("CKID", location.getPhyDepot().getId());
                safetyStockGapsObj.put("CKMC", location.getPhyDepot().getName());
                safetyStockGapsObj.put("SPID", product.getId());
                safetyStockGapsObj.put("SPMC", product.getName());
                safetyStockGapsObj.put("AQKC", safetyStockGap.getSafetyStockQty());
                safetyStockGapsObj.put("ZDXL", safetyStockGap.getTheMinQty());
                safetyStockGapsObj.put("KYS", safetyStockGap.getUsableQty());
                safetyStockGapsObj.put("DHZT", safetyStockGap.getPurchasingWayQty());
                safetyStockGapsObj.put("ZCSHZT", safetyStockGap.getTransferReceiveQty());
                safetyStockGapsObj.put("BCQKSL", safetyStockGap.getGapQty());
                safetyStockGapsObj.put("HJSL", safetyStockGap.getTotalQty());
                safetyStockGapsObj.put("YRKSL", safetyStockGap.getWarehousingQty());
                safetyStockGapsObj.put("ZCSL", safetyStockGap.getAssignedQty());
                safetyStockGapsObj.put("XKJDHBJ", 1);
                array.add(safetyStockGapsObj);
            }
        });

        JSONObject AQKCQKParam = new JSONObject();
        AQKCQKParam.put("TABLE", "RPT_AQKCQKRBB");
        AQKCQKParam.put("items", array);
        piManager.synErp("scmKckzService.insertAQKCQK", AQKCQKParam);
    }



    /*****************************************自动转储*********************************************************************************************************************/

    @Autowired
    private TransactionTemplate transactionTemplate;
    public void execute(Callback callback) {
        transactionTemplate.execute(status -> {
            try {
                callback.execute();
                return null;
            } catch (Exception e) {
                status.isRollbackOnly();
                throw e;
            }
        });
    }

    @FunctionalInterface
    public interface Callback {
        @Nullable
        void execute();
    }






    @OutboxSubscriber(id = "local:autoProductRequireDumpService.asySafetyStockRelenishment", name = "安全库存执行")
    public void asySafetyStockRelenishment(OutboxPayloadWrapper outboxPayloadWrapper) {
        if (!DateUtil.format(JSONObject.parseObject(outboxPayloadWrapper.getPayload()).getDate("currentDate"), DateUtil.SHOW_DATE_FORMAT).equals(DateUtil.format(new Date(), DateUtil.SHOW_DATE_FORMAT))) return;
        invoke("stock.autoProductRequireDumpService.safetyStockRelenishment", outboxPayloadWrapper.getPayload());
    }

    @OutboxSubscriber(id = "local:autoProductRequireDumpService.insertPurchaseOrder", name = "老切新, 要货单生成采购订单")
    public void insertPurchaseOrder(OutboxPayloadWrapper outboxPayloadWrapper) {
        invoke("stock.replenishmentManagementService.insertPurchaseOrder_external", outboxPayloadWrapper.getPayload());
    }


    public void writeRequireMongoLog(Map param) {
        Document column = new Document();
        column.putAll(param);
        column.put("currentDate", DateUtil.format(new Date(), DateUtil.SHOW_DATE_FORMAT));
        mongoTemplate.getCollection("autoSafetyStockLog").insertOne(column);
    }

}




















